package puntaelena.facilitylocation.hillclimbing.experiment.grszcompetitive;

import puntaelena.graphsupport.FacilitiesGraph;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;

import laboratoryQ.computation.flatness.*;
import laboratoryQ.experiment.IExperimentResult;
import laboratoryQ.experiment.reportage.ui.diagram2component.IDiagramsExtractor;
import laboratoryQ.experiment.reportage.ui.diagram2component.ITitlesExtractor;

public class PElenaGSCDiagramExtractor
	implements IDiagramsExtractor, ITitlesExtractor
{
	@Override
	public List<DiagramData[]> extractDiagrams(
			IExperimentResult expResult
		) {
		PElenaGSCExperimentContext context =
			(PElenaGSCExperimentContext) expResult;
		PElenaGSCExperimentSettings settings =
			context.getExperimentSettings();
		List<DiagramData[]> result =
			new ArrayList<DiagramData[]>();

		NeighborAverageFilter nghAvFilter = new NeighborAverageFilter();
		nghAvFilter.setAlfa(0.35);
		nghAvFilter.setIterations(4);
		ReplaceInfFilter rinfFilter =
			new ReplaceInfFilter(FacilitiesGraph.DEFAULT_INF_EDGE / 2);
		CompoundFilter filter = new CompoundFilter(rinfFilter, nghAvFilter);
		IGraphFilter costFilter = filter;
		IGraphFilter benefitFilter = filter;
		IGraphFilter coalitionsFilter = filter;

		if (context.graphSizeCosts != null) {
			addDiagram(
				context.graphSizeCosts,
				settings.citiesCountBeg,
				settings.citiesCountEnd,
				result,
				costFilter
			);

			List<double[]> stratBenefit =
				getBenefitsDiaList(context.graphSizeCosts, settings);
			addDiagram(
				stratBenefit,
				settings.citiesCountBeg,
				settings.citiesCountEnd,
				result,
				benefitFilter
			);
		}

		if (
			context.coalitionsReport != null &&
			context.enemiesReport != null
		) {
			addDiagram(
				Arrays.<double[]>asList(
					int2double(context.coalitionsReport),
					int2double(context.enemiesReport)
				),
				settings.citiesCountBeg,
				settings.citiesCountEnd,
				result,
				coalitionsFilter);
		}

		return result;
	}

	private List<double[]> getBenefitsDiaList(
		List<double[]> graphSizeCosts,
		PElenaGSCExperimentSettings settings
	) {
		List<double[]> stratBenefit = new ArrayList<double[]>();
		for (
			Entry<Integer,Integer> benefitItem :
				settings.getBenefitObservationItems()
		) {
			int benefitPos = benefitItem.getKey();
			int basePos = benefitItem.getValue();
			double[] benefdia = graphSizeCosts.get(benefitPos);
			double[] basedia = graphSizeCosts.get(basePos);
			int n = benefdia.length;
			double[] theBenefitDia = new double[n];
			for (int i = 0; i < n; i++) {
				theBenefitDia[i] = basedia[i] - benefdia[i];
			}
			stratBenefit.add(theBenefitDia);
		}
		return stratBenefit;
	}

	private static double[] int2double(int[] src) {
		int n = src.length;
		double[] result = new double[n];
		for (int i = 0; i < n; i++) {
			result[i] = src[i];
		}
		return result;
	}

	private void addDiagram(
		List<double[]> diaSrc,
		int citiesCountBeg,
		int citiesCountEnd,
		List<DiagramData[]> result,
		IGraphFilter filter
	) {
		int count = citiesCountEnd - citiesCountBeg + 1;
		double[] xs = new double[count];
		for (int i = 0; i < count; i++) {
			xs[i] = citiesCountBeg + i;
		}
		DiagramData[] dia = new DiagramData[diaSrc.size()];
		for (int i = 0; i < dia.length; i++) {
			double[] observations = diaSrc.get(i);
			observations = filter.apply(observations);
			dia[i] = new DiagramData(xs, observations);
		}
		result.add(dia);
	}

	@Override
	public List<String> getTitles(IExperimentResult expResult) {
		return Arrays.asList(
			"Cities count -> total cost",
			"Benefit of against policy",
			"Coalitions"
		);
	}

	@Override
	public List<String> getXCaptions(IExperimentResult expResult) {
		return Arrays.asList(
			"Cities count",
			"Cities count",
			"Cities count"
		);
	}

	@Override
	public List<String> getYCaptions(IExperimentResult expResult) {
		return Arrays.asList(
			"Cost",
			"Benefit",
			"Big coalition population"
		);
	}
}
